from datetime import datetime
import json
import logging

from django.shortcuts import render
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from orders.models import Order
from payments.models import PaymentRecord
from payments.wxpay import WxPayClient
from utils.snowflake_singleton import SnowflakeSingleton
from payments.tasks import send_order_success_email

# Create your views here.

logger = logging.getLogger('django')


class WxPayOrderAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """
        微信支付下单接口
        """
        # 获取参数:订单号
        order_number = request.data.get('order_number')
        if not order_number:
            return Response({'code': 0, 'message': '订单号不能为空'})

        try:
            order = Order.objects.get(order_number=order_number, user=request.user)

            # 判断订单状态
            if order.order_status != 0:
                return Response({'code': 0, 'message': '订单状态有误'})

            snowflake = SnowflakeSingleton.get_instance(worker_id=2)
            pay_order_number = str(snowflake.get_id())
            logger.info(f"微信支付订单号:{pay_order_number}")

            payment_record = PaymentRecord.objects.create(
                order=order,
                order_number=order_number,
                pay_order_number=pay_order_number,
                trade_no='',
                pay_method=2,
                pay_amount=order.real_price,
                pay_status=0
            )
            logger.info(f"创建了一条支付记录数据:{payment_record}")
            total_fee = int(float(order.real_price) * 100)
            description = f"码境空间课程订单:{pay_order_number}"
            client = WxPayClient()
            code_url = client.create_order(pay_order_number, total_fee, description)
            if not code_url:
                return Response({"code": 0, "message": "微信支付下单失败"})
            payment_record.pay_remark = "发起微信支付成功"
            payment_record.save()

            order.pay_method = 2
            order.save()

            result = {
                "pay_order_number": pay_order_number,
                "pay_url": code_url,
                "total_fee": total_fee,
                "order_number": order_number
            }

            return Response({
                "code": 1,
                "message": "微信下单成功",
                "data": result
            })
        except Exception as e:
            logger.error(f"微信下单失败:{str(e)}")
            return Response({
                "code": 0,
                "message": f"微信下单失败:{str(e)}"
            })


@method_decorator(csrf_exempt, name='dispatch')
class WxPayNotifyApiView(APIView):
    """
    微信支付结果通知回调接口
    """
    # 不需要身份验证，因为是微信服务器发起的回调请求
    authentication_classes = []
    permission_classes = []

    def post(self, request):
        try:
            logger.info("微信支付结果通知回调接口-----------------")
            body_bytes = request.body or b''
            payload = json.loads(body_bytes.decode('utf-8')) if body_bytes else {}

            event_type = payload.get('event_type')
            resource = payload.get('resource') or {}
            logger.info(f'微信回调资源体: {resource}')

            if not resource:
                logger.error('微信回调资源体为空')
                return Response({'code': 'FAIL', 'message': 'Bad Request'}, status=400)

            client = WxPayClient()
            # 可选：如启用平台证书，可先验签
            if not client.verify_callback_signature(request.headers, body_bytes.decode('utf-8')):
                logger.error('微信回调验签失败')
                return Response({'code': 'FAIL', 'message': 'Signature Verify Fail'}, status=401)

            try:
                decrypted = client.decrypt_notification(resource)
            except Exception as decrypt_err:
                logger.error(f'微信回调解密失败: {decrypt_err}')
                return Response({'code': 'FAIL', 'message': 'Decrypt Fail'}, status=400)

            # 解密后的交易数据（参考官方文档）
            out_trade_no = decrypted.get('out_trade_no')
            transaction_id = decrypted.get('transaction_id')
            trade_state = decrypted.get('trade_state')
            success_time_str = decrypted.get('success_time')
            amount_info = decrypted.get('amount') or {}
            payer_info = decrypted.get('payer') or {}

            # 非成功事件可直接忽略返回成功（避免微信重试）
            if trade_state != 'SUCCESS' or event_type != 'TRANSACTION.SUCCESS':
                logger.info(
                    f'非成功回调，已忽略: trade_state={trade_state}, event_type={event_type}, out_trade_no={out_trade_no}')
                return Response({'code': 'SUCCESS', 'message': '成功'})

            # 幂等：若记录已成功处理，则直接返回
            payment_record = PaymentRecord.objects.filter(pay_order_number=out_trade_no).order_by('-id').first()
            if not payment_record:
                logger.error(f'未找到支付记录: out_trade_no={out_trade_no}')
                return Response({'code': 'FAIL', 'message': 'Payment Record Not Found'}, status=404)

            if payment_record.pay_status == 1 and payment_record.trade_no:
                logger.info(f'重复回调，已处理过: out_trade_no={out_trade_no}')
                return Response({'code': 'SUCCESS', 'message': '成功'})

            # 订单金额校验（单位：分）
            total_paid_cents = int(amount_info.get('total') or 0)
            expected_cents = int(float(payment_record.pay_amount) * 100)
            if total_paid_cents != expected_cents:
                logger.error(
                    f'金额不匹配: notify={total_paid_cents}, expected={expected_cents}, out_trade_no={out_trade_no}')
                return Response({'code': 'FAIL', 'message': 'Amount Mismatch'}, status=400)

            # 更新支付记录
            payment_record.pay_status = 1
            payment_record.trade_no = transaction_id
            try:
                if success_time_str:
                    # 例如: 2020-12-31T15:01:02+08:00 -> 转为本地时区的“无时区”时间（兼容 USE_TZ=False）
                    parsed_dt = datetime.fromisoformat(success_time_str)
                    if timezone.is_aware(parsed_dt):
                        local_dt = parsed_dt.astimezone(timezone.get_current_timezone())
                        payment_record.pay_time = local_dt.replace(tzinfo=None)
                    else:
                        payment_record.pay_time = parsed_dt
                else:
                    payment_record.pay_time = timezone.now()
            except Exception:
                payment_record.pay_time = timezone.now()
            payment_record.pay_remark = '微信支付成功'
            payment_record.save()

            # 同步更新订单
            order = payment_record.order
            order.order_status = 1
            order.trade_no = transaction_id
            try:
                if success_time_str:
                    parsed_dt = datetime.fromisoformat(success_time_str)
                    if timezone.is_aware(parsed_dt):
                        local_dt = parsed_dt.astimezone(timezone.get_current_timezone())
                        order.pay_time = local_dt.replace(tzinfo=None)
                    else:
                        order.pay_time = parsed_dt
                else:
                    order.pay_time = timezone.now()
            except Exception:
                order.pay_time = timezone.now()
            order.save()

            # 发送邮件通知（异步，仅在微信回调成功后）
            try:

                user = order.user
                to_email = getattr(user, "email", None)
                logger.info(f'查询成功，发送邮件任务派发:{to_email}')
                if to_email:
                    course_names = [
                        od.course.name for od in order.order_details.select_related("course").all()
                    ]
                    send_order_success_email.delay(
                        to_email=to_email,
                        username=user.username,
                        order_number=order.order_number,
                        course_names=course_names,
                    )
            except Exception as mail_err:
                logger.error(f"支付成功但发送邮件任务派发失败: {mail_err}")

            return Response({'code': 'SUCCESS', 'message': '成功'})

        except Exception as e:
            logger.error(f'微信回调处理异常: {e}')
            return Response({'code': 'FAIL', 'message': 'Internal Error'}, status=500)


def parse_time(time_str):
    """处理微信支付返回的时间字符串"""
    if not time_str:
        return None
    # 将ISO格式时间字符串转换为datetime对象
    try:
        # 处理带时区的时间字符串，去除时区信息
        time_str = time_str.split('+')[0].replace('T', ' ')
        return datetime.strptime(time_str, '%Y-%m-%d %H:%M:%S')
    except Exception as e:
        logger.error(f"时间解析异常：{str(e)}")
        return None


class WxPayQueryAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        """
        查询订单状态
        """
        order_number = request.query_params.get('order_number')
        pay_order_number = request.query_params.get('pay_order_number')

        if not order_number or not pay_order_number:
            return Response({'code': '0', 'message': '参数错误'})

        try:
            # 查询订单状态
            order = Order.objects.get(order_number=order_number, user=request.user)
            if order.order_status == 1:
                return Response({'code': '1', 'message': '订单已支付'})

            try:
                payment_record = (
                    PaymentRecord.objects.get(order_number=order_number,
                                              pay_order_number=pay_order_number,
                                              pay_method=2))
            except PaymentRecord.DoesNotExist:
                return Response({'code': '0', 'message': '订单记录不存在'})

            client = WxPayClient()
            result = client.query_order(pay_order_number)
            logger.info(f"微信支付查询结果:{result}")
            trade_state = result.get("trade_state")
            if trade_state == "SUCCESS":
                logger.info(f'微信支付成功: pay_order_number={pay_order_number}')
                order.order_status = 1
                order.trade_no = result.get("transaction_id")
                order.pay_time = parse_time(result.get("success_time"))
                order.save()

                payment_record.pay_status = 1
                payment_record.trade_no = result.get("transaction_id")
                payment_record.pay_time = parse_time(result.get("success_time"))
                payment_record.pay_remark = "微信支付成功"

                payment_record.save()

                # 发送邮件通知（异步，仅在查询确认支付成功后）
                try:

                    user = order.user
                    to_email = getattr(user, "email", None)
                    logger.info(f'查询成功，发送邮件任务派发:{to_email}')
                    if to_email:
                        course_names = [
                            od.course.name for od in order.order_details.select_related("course").all()
                        ]
                        send_order_success_email.delay(
                            to_email=to_email,
                            username=user.username,
                            order_number=order.order_number,
                            course_names=course_names,
                        )
                except Exception as mail_err:
                    logger.error(f"查询成功但发送邮件任务派发失败: {mail_err}")

                return Response({'code': '1', 'message': '订单已支付'})
            else:
                logger.info(f'微信支付失败: pay_order_number={pay_order_number}, trade_state={trade_state}')
                return Response({'code': '0', 'message': '订单未支付'})
        except Exception as e:
            logger.error(f'微信支付查询异常: {e}')
            return Response({'code': '0', 'message': '查询异常'})


class WxRefundApplyAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def post(self, request):
        """
        微信申请退款
        入参：
        - order_number 或 pay_order_number（二选一）
        - refund_amount 可选，单位：元（小数）；不传则全额退款
        - reason 可选，退款原因
        """
        order_number = request.data.get('order_number')
        pay_order_number = request.data.get('pay_order_number')
        refund_amount_yuan = request.data.get('refund_amount')  # 字符串/数字，单位：元
        reason = request.data.get('reason')

        # 未登录直接拒绝（双保险，避免匿名用户进入业务逻辑）
        if not getattr(request.user, 'is_authenticated', False):
            return Response({'code': 0, 'message': '未登录'}, status=401)

        if not order_number and not pay_order_number:
            return Response({'code': 0, 'message': '参数错误：需要提供 order_number 或 pay_order_number'})

        try:
            # 获取支付记录（仅微信，且已支付）
            qs = PaymentRecord.objects.filter(order__user_id=request.user.id, pay_method=2, pay_status=1)
            if order_number:
                qs = qs.filter(order_number=order_number)
            if pay_order_number:
                qs = qs.filter(pay_order_number=pay_order_number)
            payment_record = qs.order_by('-id').first()
            if not payment_record:
                return Response({'code': 0, 'message': '未找到已支付的支付记录'})

            order = payment_record.order
            if order.order_status != 1:
                return Response({'code': 0, 'message': '订单未处于已支付状态，无法退款'})

            total_fee = int(float(payment_record.pay_amount) * 100)
            if refund_amount_yuan is None or refund_amount_yuan == '':
                refund_fee = total_fee
            else:
                try:
                    refund_fee = int(float(refund_amount_yuan) * 100)
                except Exception:
                    return Response({'code': 0, 'message': 'refund_amount 非法'})
                if refund_fee <= 0 or refund_fee > total_fee:
                    return Response({'code': 0, 'message': '退款金额不合法'})

            out_trade_no = payment_record.pay_order_number
            snowflake = SnowflakeSingleton.get_instance(worker_id=2)
            out_refund_no = str(snowflake.get_id())

            client = WxPayClient()
            result = client.create_refund(
                out_trade_no=out_trade_no,
                out_refund_no=out_refund_no,
                refund_fee=refund_fee,
                total_fee=total_fee,
                reason=reason,
            )

            if not result:
                return Response({'code': 0, 'message': '微信退款申请失败'})

            return Response({
                'code': 1,
                'message': '微信退款申请已提交',
                'data': {
                    'out_refund_no': out_refund_no,
                    'wx_result': result,
                }
            })
        except Exception as e:
            logger.error(f'微信退款申请异常: {e}')
            return Response({'code': 0, 'message': '退款申请异常'})


class WxRefundQueryAPIView(APIView):
    permission_classes = [IsAuthenticated]

    def get(self, request):
        """
        查询微信单笔退款状态
        入参：out_refund_no（商户退款单号）
        """
        out_refund_no = request.query_params.get('out_refund_no')
        if not out_refund_no:
            return Response({'code': 0, 'message': '参数错误：缺少 out_refund_no'})

        try:
            client = WxPayClient()
            result = client.query_refund(out_refund_no)
            if not result:
                return Response({'code': 0, 'message': '退款查询失败'})

            return Response({
                'code': 1,
                'message': '查询成功',
                'data': result,
            })
        except Exception as e:
            logger.error(f'微信退款查询异常: {e}')
            return Response({'code': 0, 'message': '查询异常'})
